package com.superhero.website.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.poi.excel.ExcelWriter;
import com.superhero.common.Enum.RoleType;
import com.superhero.common.exception.BusinessException;
import com.superhero.common.pojo.PageInput;
import com.superhero.common.pojo.entity.AuthUser;
import com.superhero.common.pojo.vo.PageVo;
import com.superhero.common.pojo.vo.website.InspectorInput;
import com.superhero.common.pojo.vo.website.InspectorListVo;
import com.superhero.common.repository.AuthUserRepository;
import com.superhero.common.utils.ExcelUtils;
import com.superhero.common.utils.OptionalUtil;
import com.superhero.website.service.InspectorService;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;

@Service
public class InspectorServiceImpl implements InspectorService {

    @Autowired
    AuthUserRepository authUserRepository;
    @Resource
    BCryptPasswordEncoder passwordEncoder;

    @Override
    public void getAuthUser(InspectorInput input, AuthUser user) {
        user.setUsername(input.getUsername());
        user.setRealName(input.getRealName());
        user.setIdCard(input.getIdCard());
        user.setPhone(input.getPhone());
        user.setRole(2);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public AuthUser append(InspectorInput input) {
        Optional<AuthUser> authUserByUsername = authUserRepository.findAuthUserByUsername(input.getUsername());
        if (authUserByUsername.isPresent()) {
            throw new BusinessException("该用户名已被使用！");
        }
        AuthUser authUser = new AuthUser();
        getAuthUser(input, authUser);
        authUser.setPassword(passwordEncoder.encode(input.getPassword()));
        AuthUser save = authUserRepository.save(authUser);
        return save;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public AuthUser update(InspectorInput input) {
        AuthUser authUser = OptionalUtil.get(authUserRepository.findById(input.getId()));
        if (!authUser.getUsername().equals(input.getUsername())) {
            Optional<AuthUser> authUserByUsername = authUserRepository.findAuthUserByUsername(input.getUsername());
            if (authUserByUsername.isPresent() && authUser.getUsername().equals(input.getUsername())) {
                throw new BusinessException("该用户名已被使用！");
            }
        }
        getAuthUser(input, authUser);
        if (!authUser.getPassword().contains("******")) {
            authUser.setPassword(passwordEncoder.encode(input.getPassword()));
        }
        authUser.setId(input.getId());
        AuthUser save = authUserRepository.save(authUser);
        return save;
    }

    @Override
    public InspectorListVo getDetail(Integer id) {
        AuthUser authUser = OptionalUtil.get(authUserRepository.findById(id));
        if (authUser.getRole() != 2) {
            throw new BusinessException("找不到该记录");
        }
        InspectorListVo inspectorListVo = new InspectorListVo();
        inspectorListVo.setId(authUser.getId());
        inspectorListVo.setUsername(authUser.getUsername());
        inspectorListVo.setRealName(authUser.getRealName());
        inspectorListVo.setPhone(authUser.getPhone());
        inspectorListVo.setIdCard(authUser.getIdCard());

        return inspectorListVo;
    }

    @Override
    public ExcelWriter getExcelWriter(String keyword) {
        // 查询导出列表
        List<AuthUser> inspectors = authUserRepository.findAll(((root, criteriaQuery, criteriaBuilder) -> {
            List<Predicate> predicates = getPredicate(root, criteriaBuilder, keyword);
            Predicate[] p = new Predicate[predicates.size()];
            criteriaQuery.orderBy(criteriaBuilder.desc(root.get("createTime")));
            return criteriaBuilder.and(predicates.toArray(p));
        }));
        List<InspectorListVo> inspectorListVos = inspectors.stream().map(inspector -> {
            InspectorListVo inspectorListVo = new InspectorListVo();
            BeanUtils.copyProperties(inspector, inspectorListVo);
            return inspectorListVo;
        }).collect(Collectors.toList());

        if (!CollectionUtil.isEmpty(inspectorListVos)) {
            // 设置模板头顺序
            ExcelWriter writer = getListExcelWriter();
            // 进行写入
            return ExcelUtils.doExcelWriter(null, writer, inspectorListVos, InspectorListVo.class);
        }
        return null;
    }

    private ExcelWriter getListExcelWriter() {
        ExcelWriter writer = new ExcelWriter(true);
        writer.addHeaderAlias("id", "代码");
        writer.addHeaderAlias("username", "用户名");
        writer.addHeaderAlias("realName", "真实姓名");
        writer.addHeaderAlias("phone", "手机号");
        writer.addHeaderAlias("idCard", "身份证号");
        return writer;
    }

    @Override
    public PageVo showList(PageInput queryInput, String keyword) {
        Pageable pageable = PageRequest.of(queryInput.getPageNumber(), queryInput.getPageSize());
        Page<AuthUser> inspectors = authUserRepository.findAll(((root, criteriaQuery, criteriaBuilder) -> {
            List<Predicate> predicates = getPredicate(root, criteriaBuilder, keyword);
            Predicate[] p = new Predicate[predicates.size()];
            criteriaQuery.orderBy(criteriaBuilder.desc(root.get("createTime")));
            return criteriaBuilder.and(predicates.toArray(p));
        }), pageable);

        PageVo result = PageVo.convert(inspectors);
        result.setContent(inspectors.getContent().stream()
                .map(inspector -> {
                    InspectorListVo inspectorListVo = new InspectorListVo();
                    BeanUtils.copyProperties(inspector, inspectorListVo);
                    return inspectorListVo;
                }).collect(Collectors.toList()));
        return result;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void delete(Integer id) {
        AuthUser authUser = OptionalUtil.get(authUserRepository.findById(id));
        if (authUser.getRole() != 2)
            throw new BusinessException("找不到该记录");
        authUser.setLocked(1);
        authUserRepository.save(authUser);
    }

    private List<Predicate> getPredicate(Root<AuthUser> root, CriteriaBuilder criteriaBuilder, String keyword) {
        List<Predicate> predicates = new ArrayList<>();

        predicates.add(criteriaBuilder.equal(root.get("role"), RoleType.INSPECTOR.ordinal()));
        predicates.add(criteriaBuilder.equal(root.get("locked"), "0"));
        if (!StringUtils.isEmpty(keyword)) {
            String key = "%" + keyword.trim() + "%";
            String upperKey = "%" + keyword.toUpperCase().trim() + "%";

            // 关键字查询
            Predicate p1 = null, p2 = null, p3 = null;
            p1 = criteriaBuilder.like(criteriaBuilder.upper(root.get("username")), upperKey);
            p2 = criteriaBuilder.like(criteriaBuilder.upper(root.get("realName")), upperKey);
            p3 = criteriaBuilder.like(root.get("phone"), key);
            predicates.add(criteriaBuilder.or(p1, p2, p3));
        }
        return predicates;
    }
}